import { promises as fs } from 'fs'
import moment from 'moment'
import 'moment/locale/zh-cn'
import * as path from 'path'
import winston from 'winston'
import 'winston-daily-rotate-file'

class Logger {
  private logger: winston.Logger
  private readonly LOG_DIR = 'logs'
  private readonly MAX_FILES = '30d' // 保留30天的日志
  private readonly MAX_SIZE = '100m' // 每个文件最大100MB

  constructor() {
    moment.locale('zh-cn')
    this.initializeLogger()
  }

  private initializeLogger() {
    const logDir = path.join(process.cwd(), this.LOG_DIR)

    // 定义日志格式
    const logFormat = winston.format.combine(
      winston.format.timestamp({
        format: () => moment().format('YYYY-MM-DD HH:mm:ss'),
      }),
      winston.format.errors({ stack: true }),
      winston.format.splat(),
      winston.format.json(),
      winston.format.printf(({ level, message, timestamp, stack, ...meta }) => {
        let log = `[${timestamp}] [${level.toUpperCase()}]: ${message}`
        if (stack) log += `\n${stack}`
        if (Object.keys(meta).length > 0) {
          log += `\n${JSON.stringify(meta, null, 2)}`
        }
        return log
      })
    )

    // 创建日志传输器
    const transports = [
      // 错误日志
      new (require('winston-daily-rotate-file'))({
        filename: path.join(logDir, 'error-%DATE%.log'),
        datePattern: 'YYYY-MM-DD',
        maxSize: this.MAX_SIZE,
        maxFiles: this.MAX_FILES,
        level: 'error',
        format: logFormat,
      }),

      // 普通日志
      new (require('winston-daily-rotate-file'))({
        filename: path.join(logDir, 'combined-%DATE%.log'),
        datePattern: 'YYYY-MM-DD',
        maxSize: this.MAX_SIZE,
        maxFiles: this.MAX_FILES,
        format: logFormat,
      }),

      // 控制台输出(开发环境)
      new winston.transports.Console({
        format: winston.format.combine(winston.format.colorize(), winston.format.simple()),
      }),
    ]

    // 创建日志实例
    this.logger = winston.createLogger({
      level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
      transports,
      exitOnError: false,
    })

    // 捕获未处理的异常和Promise拒绝
    this.handleUncaughtExceptions()
  }

  private handleUncaughtExceptions() {
    process.on('uncaughtException', (error) => {
      this.error('未捕获的异常:', error)
      if (process.env.NODE_ENV === 'production') {
        process.exit(1)
      }
    })

    process.on('unhandledRejection', (reason) => {
      this.error('未处理的Promise拒绝:', reason)
    })
  }

  // 日志级别方法
  public debug(message: string, ...meta: any[]) {
    this.logger.debug(message, ...meta)
  }

  public info(message: string, ...meta: any[]) {
    this.logger.info(message, ...meta)
  }

  public warn(message: string, ...meta: any[]) {
    this.logger.warn(message, ...meta)
  }

  public error(message: string, ...meta: any[]) {
    this.logger.error(message, ...meta)
  }

  // 性能日志
  public logPerformance(operation: string, startTime: number) {
    const duration = Date.now() - startTime
    this.info(`性能统计 - ${operation}: ${duration}ms`)
  }

  // 访问日志
  public logAccess(req: any, res: any, responseTime: number) {
    const log = {
      timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
      method: req.method,
      url: req.originalUrl,
      status: res.statusCode,
      responseTime: `${responseTime}ms`,
      ip: req.ip,
      userAgent: req.get('user-agent'),
    }

    this.info('访问日志', log)
  }

  // 业务日志
  public logBusiness(type: string, data: any) {
    this.info(`业务日志 - ${type}`, {
      ...data,
      timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
    })
  }

  // 安全日志
  public logSecurity(event: string, details: any) {
    this.warn(`安全日志 - ${event}`, {
      ...details,
      timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
    })
  }

  // 获取日志文件列表
  public async getLogFiles(): Promise<any[]> {
    try {
      const logDir = path.join(process.cwd(), this.LOG_DIR)
      const files = await fs.readdir(logDir)

      return files
        .filter((file) => file.endsWith('.log'))
        .map((file) => ({
          name: file,
          path: path.join(logDir, file),
          date: file.match(/\d{4}-\d{2}-\d{2}/)?.[0] || '',
        }))
        .sort((a, b) => b.date.localeCompare(a.date))
    } catch (error) {
      this.error('获取日志文件列表失败:', error)
      return []
    }
  }
}

export const logger = new Logger()
